package com.bdcom.autotest.telnet;

import com.bdcom.autotest.config.ClientStartRun;
import com.bdcom.autotest.telnet.constant.TelnetConstant;
import com.bdcom.autotest.telnet.constant.TransmissionConstant;
import com.bdcom.autotest.telnet.util.ping.Ping;
import net.sf.json.JSONArray;
import org.apache.commons.net.telnet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Vector;

/**
 * 用于Telnet登陆设备，专门执行备份下发配置，升级备份版本命令
 *
 */
public class TelnetExecuteCMD implements ITransmissionServer, TelnetNotificationHandler, TransmissionConstant {
	private static final Logger logger = LoggerFactory.getLogger(ClientStartRun.class);
	
	private TelnetClient telnetClient = null;
	
	private OutputStream outprint;
	private InputStream inputStream;
	
	private String errMessage="";
	
	//端口
    private int port;

    //telnet 用户名
    private String user;
    
    //telnet 密码
    private String password;
    
    //enable 密码
    private String enablePassword;
    
    //要执行的cmd命令
    private String cmd;

    //ip地址
    private String ip;
    private Vector<String> cmds;

    public Vector<String> getCmds() {
		return cmds;
	}

	public void setCmds(Vector<String> cmds) {
		this.cmds = cmds;
	}
	
	public TelnetExecuteCMD(String ip, String user, String password , String enablePassword, String cmd) {
        this.ip = ip;
        this.port = TelnetConstant.defaultPort;
        this.user = user;
        this.password = password;
        this.enablePassword=enablePassword;
        this.cmd = cmd;
    }

    public TelnetExecuteCMD(String ip, int port, String user, String password , String enablePassword, String cmd) {
        this.ip = ip;
        this.port = port;
        this.user = user;
        this.password = password;
        this.enablePassword = enablePassword;
        this.cmd = cmd;
    }

	@Override
	public Properties executeResult() {
		Properties retProperties = new Properties();
		boolean isPing = false;
		try{
			isPing = Ping.ping(ip);
			if(!isPing){
				retProperties.setProperty(EXECUTE_RESULT, "Failure");
				retProperties.setProperty(EXECUTE_DESC, "{0} Cant ping");
				JSONArray descArgs = new JSONArray();
				descArgs.add(ip);
				retProperties.put(EXECUTE_ARGS, descArgs);
				return retProperties;
			}
			boolean isConnect = connectAndLogin();
			if (!isConnect) {
				retProperties.setProperty(EXECUTE_RESULT, "Failure");
				retProperties.setProperty(EXECUTE_DESC, "{0} Cant Telnet,Maybe Username or Password error! Username{1} Password{2} EnablePassword{3}");
				JSONArray descArgs = new JSONArray();
				descArgs.add(ip);
				descArgs.add(user);
				descArgs.add(password);
				descArgs.add(enablePassword);
				retProperties.put(EXECUTE_ARGS, descArgs);
				return retProperties;
			}
			//执行cmd命令
			boolean isSucceed =executeStatus(sendCommand(cmd), cmd);
//			boolean isSucceed = true;
			disConnect();
			if (isSucceed) {
				retProperties.setProperty(EXECUTE_RESULT, "Success");
				retProperties.setProperty(EXECUTE_DESC, "{0} succeed");
				JSONArray descArgs = new JSONArray();
				descArgs.add(ip);
				retProperties.put(EXECUTE_ARGS, descArgs);
				return retProperties;
			}else{
				retProperties.setProperty(EXECUTE_RESULT, "Failure");
				retProperties.setProperty(EXECUTE_DESC, "{0} Execute cmd failed! {1}");
				JSONArray descArgs = new JSONArray();
				descArgs.add(ip);
				descArgs.add(errMessage);
				retProperties.put(EXECUTE_ARGS, descArgs);
				return retProperties;
			}
		} catch (Exception e) {
			logger.error("" ,e );
		}
		return retProperties;
	}
	
	 /**
     * @return boolean 连接成功返回true，否则返回false
     */
    private boolean connectAndLogin() {
        TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler("VT220", false, false, true, false);// telnet有VT100 VT52  VT220 VTNT ANSI等协议。
        EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true, false);
        SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true, true, true);
        String retStr = "";
        try {
        	telnetClient = new TelnetClient();
        	telnetClient.addOptionHandler(ttopt);
			telnetClient.addOptionHandler(echoopt);
			telnetClient.addOptionHandler(gaopt);
			telnetClient.setConnectTimeout(5000); //socket延迟时间：5000ms
			
        	
			telnetClient.connect(ip, port);
			telnetClient.registerNotifHandler(this);
			
			outprint = telnetClient.getOutputStream(); 
			inputStream = telnetClient.getInputStream();
			//进行登录
			 retStr = readUntil("");
			  if(retStr.endsWith(USERNAME)){
				  retStr = sendCommand(user);
				  if(retStr.endsWith(TELNET_PASSWORD)){
					  retStr = sendCommand(password);
				  }else{
					  errMessage = retStr;
					  return false;
				  }
			  }
			  //说明登陆成功 (有可能不需要用户名和 密码记性登陆), 进行enable
			  if(retStr.endsWith(ENTER_COMMAND_ARROW)){
				  retStr = sendCommand("enable");
				  if(retStr.endsWith(PASSWORD)){
					  //说明需要enable密码
					  retStr = sendCommand(enablePassword);
					  if(!retStr.endsWith(DEFAULT_AIX_PROMPT)){
						  errMessage = retStr;
						  return false;
					  }
				  }
				  
			  }else{
				  errMessage = LOGIN_FAILED;
				  return false;
			  }
			  
        } catch (Exception e) {
        	logger.error("Telnet Connect error!",e);
            return false;
        }
        return telnetClient.isConnected();
    }
    
    
    
    
	public void disConnect() throws Exception{
		try {
			if (telnetClient != null && telnetClient.isConnected()){
				telnetClient.disconnect();
			}
		} catch (Exception e) {
			throw new Exception("Disconnect telnet client error!", e);
		}
	}
	
	  
	    
	  
	  public String sendCommand(String command) {
	        try {
//	        	outprint.write((command+"\n").getBytes("utf-8"));
//	            outprint.flush();
	        	outprint.write(command.getBytes("utf-8"));
	        	outprint.write(13);
	        	outprint.write(10);
	        	outprint.flush();
	            return readUntil(command);
	        } catch (Exception e) {
	        	logger.error("",e);
	        }
	        return null;
	    }
	  
	  
	    public String readUntil(String command) {
	    	
	        try {
	        	StringBuffer sb = new StringBuffer();
	            char ch = (char) inputStream.read();
	            long beginTime =System.currentTimeMillis();
	            while (true) {
	            	sb.append(ch);
	            	
	            	if(command!=null && command.equals(ENABLE)){
	            		if (sb.toString().endsWith(DEFAULT_AIX_PROMPT)) {
	            			return sb.toString();
						}if(sb.toString().endsWith(PASSWORD)) {
							return sb.toString();
						}
	            	}else{
	            		if(sb.toString().endsWith(USERNAME) || sb.toString().endsWith(TELNET_PASSWORD)
	            				||sb.toString().endsWith(ENTER_COMMAND_ARROW)
	            				||sb.toString().endsWith(SUCCEED)||sb.toString().endsWith(TIMEOUT)
	            				||sb.toString().endsWith(SERVER_IP_ERROR)||sb.toString().endsWith(MALLOC_FAIL)
	            				||sb.toString().endsWith(FILESYS_BUSY)||sb.toString().endsWith(UNABLE_GET_FILE_SIZE)
	            				||sb.toString().endsWith(MEMORY_ALLOC_ERROR)||sb.toString().endsWith(FREE_SPACE_NOT_ENOUGH)
	            				||sb.toString().endsWith(ENTER_FILESYS_ERROR)||sb.toString().endsWith(OPEN_FILE_ERROR)
	            				||sb.toString().endsWith(WRITE_FILE_ERROR)||sb.toString().endsWith(FILE_CLOSE_ERROR)
	            				||sb.toString().endsWith(COPY_ERROR)||sb.toString().endsWith(SYS_MEY_ERROR)
	            				||sb.toString().endsWith(COPY_ERROR_NOT_WRITE_FLASH)||sb.toString().endsWith(PASSWORD)
	            				||sb.toString().endsWith(ERROR_ENABLE)||sb.toString().endsWith(ACCESS_DENIED)||sb.toString().endsWith(ERROR_FROM_SERVER)
	            				||sb.toString().endsWith(UNKNOW_COMMAND)||sb.toString().endsWith(USER)||(sb.toString().endsWith(DEFAULT_AIX_PROMPT)&&!command.contains(COPY_FLASH)&&!command.contains(COPY_TFTP))) {
	            			
	            			return sb.toString();
	            	    }
	            		String tempStr=sb.toString();
	            		String second_str=tempStr.substring(0,tempStr.length()-1);//倒数第二位
						//结尾是#且倒数第二位不是#，也不是回车换行，则认为成功
	            		if(tempStr.endsWith(DEFAULT_AIX_PROMPT)&&!second_str.endsWith(DEFAULT_AIX_PROMPT)&&!second_str.endsWith("\r\n")){
                           return SUCCEED;
						}

	                }
	                long endTime =System.currentTimeMillis();
	                long value=endTime-beginTime;
	                int sbSize =sb.toString().length();
	                if(value>10*60*1000||sbSize>10000){
	                	return TIMEOUT;
	                }
	                ch = (char) inputStream.read();
	            }

	        } catch (Exception e) {
	            logger.error("",e);
	        }
	        return TIMEOUT;
	    }
	  
	    /**
	     * 根据返回字符串判断下发命令是否执行成功
	     * @param retStr
	     * @return
	     */
	    public boolean executeStatus(String retStr,String cmd){
	    	if (retStr.contains(UNKNOW_COMMAND)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+UNKNOW_COMMAND;
				return false;
			}
	    	if (retStr.contains(PARAMETER_INVALID)) {
				errMessage="cmd:"+"'"+cmd+"' "+PARAMETER_INVALID;
				return false;
			}
	    	if (retStr.contains(INCOMPLETE_COMMAND)) {
				errMessage="cmd:"+"'"+cmd+"' "+INCOMPLETE_COMMAND;
				return false;
			}
	    	if(retStr.contains(TOO_MANY_PARAM))
	    	{
	    		errMessage="cmd:"+"'"+cmd+"' "+TOO_MANY_PARAM;
				return false;
	    	}
	    	if (retStr.contains(TIMEOUT)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+TIMEOUT;
	    		return false;
			}
	    	if (retStr.contains(SUCCEED)) {
	    		
	    		return true;
			}
	    	if (retStr.contains(SERVER_IP_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+SERVER_IP_ERROR;
	    		return false;
			}
	    	if (retStr.contains(ERROR_ENABLE)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+ERROR_ENABLE;
	    		return false;
			}
	    	
	    	if (retStr.contains(MALLOC_FAIL)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+MALLOC_FAIL;
	    		return false;
			}
	    	
	    	if (retStr.contains(FILESYS_BUSY)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+FILESYS_BUSY;
	    		return false;
			}
	    	if (retStr.contains(UNABLE_GET_FILE_SIZE)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+UNABLE_GET_FILE_SIZE;
	    		return false;
			}
	    	if (retStr.contains(MEMORY_ALLOC_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+MEMORY_ALLOC_ERROR;
	    		return false;
			}
	    	if (retStr.contains(FREE_SPACE_NOT_ENOUGH)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+FREE_SPACE_NOT_ENOUGH;
	    		return false;
			}
	    	if (retStr.contains(ENTER_FILESYS_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+ENTER_FILESYS_ERROR;
	    		return false;
			}
	    	if (retStr.contains(OPEN_FILE_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+OPEN_FILE_ERROR;
	    		return false;
			}
	    	if (retStr.contains(WRITE_FILE_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+WRITE_FILE_ERROR;
	    		return false;
			}
	    	if (retStr.contains(FILE_CLOSE_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+FILE_CLOSE_ERROR;
	    		return false;
			}
	    	if (retStr.contains(COPY_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+COPY_ERROR;
	    		return false;
			}
	    	if (retStr.contains(SYS_MEY_ERROR)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+SYS_MEY_ERROR;
	    		return false;
			}
	    	if (retStr.contains(COPY_ERROR_NOT_WRITE_FLASH)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+COPY_ERROR_NOT_WRITE_FLASH;
	    		return false;
			}
	    	if (retStr.contains(ACCESS_DENIED)) {
	    		errMessage="enable password error,enablePassword:"+enablePassword;
	    		return false;
			}
	    	if (retStr.contains(ERROR_FROM_SERVER)) {
	    		errMessage="cmd:"+"'"+cmd+"' "+ERROR_FROM_SERVER;
	    		return false;
			}
	    	if (retStr.contains(USER)) {
	    		errMessage="This device maybe third party device!";
	    		return false;
			}
	    	errMessage = retStr;
	    	return false;
	    }
	  
	  

    
	@Override
	public void receivedNegotiation(int negotiation_code, int option_code) {
		String command = null;
		if (negotiation_code == TelnetNotificationHandler.RECEIVED_DO) {
			command = "DO";
		} else if (negotiation_code == TelnetNotificationHandler.RECEIVED_DONT) {
			command = "DONT";
		} else if (negotiation_code == TelnetNotificationHandler.RECEIVED_WILL) {
			command = "WILL";
		} else if (negotiation_code == TelnetNotificationHandler.RECEIVED_WONT) {
			command = "WONT";
		}
	}
	

}
